package com.alex.tkmybatis.common;

import com.alex.tkmybatis.common.support.AbstractExampleWrapper;
import com.alex.tkmybatis.common.support.LambdaUtils;
import com.alex.tkmybatis.common.support.SFunction;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 *
 * 可扩展重写的Wrapper类
 * @author alexchan
 * @param <T>
 */
public class ExampleWrapper<T> extends AbstractExampleWrapper<T> {

    /**
     * @param entityClass
     */
    public ExampleWrapper(Class<?> entityClass) {
        super(entityClass);
        LambdaUtils.installCache(table);
        criteria = this.createCriteria();
    }


    /**
     * 重写的equal方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> andEqualTo(SFunction<T, ?> column, Object value) {
        criteria.andEqualTo(columnToString(column), value);
        return this;
    }

    /**
     * 重写like方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> andLike(SFunction<T, ?> column, String value) {
        criteria.andLike(columnToString(column), value);
        return this;
    }

    /**
     * 重写in方法
     *
     * @param column
     * @param values
     * @return
     */
    public ExampleWrapper<T> andIn(SFunction<T, ?> column, Iterable<String> values) {
        criteria.andIn(columnToString(column), values);
        return this;
    }

    /**
     * 重写in方法
     *
     * @param column
     * @param values
     * @return
     */
    public ExampleWrapper<T> andIn2(SFunction<T, ?> column, Iterable values) {
        criteria.andIn(columnToString(column), values);
        return this;
    }

    /**
     * 重写 > 方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> gt(SFunction<T, ?> column, Object value) {
        criteria.andGreaterThan(columnToString(column), value);
        return this;
    }

    /**
     * 重写 >= 方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> ge(SFunction<T, ?> column, Object value) {
        criteria.andGreaterThanOrEqualTo(columnToString(column), value);
        return this;
    }

    /**
     * 重写 < 方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> lt(SFunction<T, ?> column, Object value) {
        criteria.andLessThan(columnToString(column), value);
        return this;
    }

    /**
     * 重写 <= 方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> le(SFunction<T, ?> column, Object value) {
        criteria.andLessThanOrEqualTo(columnToString(column), value);
        return this;
    }


    /**
     * 重写的equal方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> andEqualNotEmpty(SFunction<T, ?> column, Object value) {
        if (value == null || (value instanceof String && StringUtils.isEmpty((String) value))) {
            return this;
        }
        criteria.andEqualTo(columnToString(column), value);
        return this;
    }

    /**
     * 重写like方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> andLikeNotEmpty(SFunction<T, ?> column, String value) {
        if (StringUtils.isEmpty(value)) {
            return this;
        }
        criteria.andLike(columnToString(column), value);
        return this;
    }


    /**
     * orlike
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> orLike(SFunction<T, ?> column, String value) {
        criteria.orLike(columnToString(column), value);
        return this;
    }

    /**
     * and
     *
     * @param other
     * @return
     */
    public ExampleWrapper<T> and(ExampleWrapper<T> other) {
        other.getOredCriteria().forEach(t -> this.and(t));
        return this;
    }

    /**
     * 重写的not equal方法
     *
     * @param column
     * @param value
     * @return
     */
    public ExampleWrapper<T> andNotEqualTo(SFunction<T, ?> column, Object value) {
        criteria.andNotEqualTo(columnToString(column), value);
        return this;
    }

    /**
     * 重写NotIn方法
     *
     * @param column
     * @param values
     * @return
     */
    public ExampleWrapper<T> andNotIn(SFunction<T, ?> column, Iterable<String> values) {
        criteria.andNotIn(columnToString(column), values);
        return this;
    }

    /**
     * 重写NotIn方法
     *
     * @param column
     * @param values
     * @return
     */
    public ExampleWrapper<T> andNotInNotEmpty(SFunction<T, ?> column, Iterable<String> values) {
        if (values == null || !values.iterator().hasNext()) {
            return this;
        }
        criteria.andNotIn(columnToString(column), values);
        return this;
    }

    /**
     * 重写andIsNotNull方法
     *
     * @param column
     * @return
     */
    public ExampleWrapper<T> andIsNotNull(SFunction<T, ?> column) {
        criteria.andIsNotNull(columnToString(column));
        return this;
    }

    /**
     * 重写andIsNull方法
     *
     * @param column
     * @return
     */
    public ExampleWrapper<T> andIsNull(SFunction<T, ?> column) {
        criteria.andIsNull(columnToString(column));
        return this;
    }


    public OrderBy orderBy(SFunction<T, ?> column) {
        return this.orderBy(columnToString(column));
    }

    /**
     * 排除字段
     *
     * @param columns
     * @return
     */
    public ExampleWrapper<T> excludeProperties(List<SFunction<T, ?>> columns) {
        if (columns == null || columns.isEmpty()) {
            return this;
        }

        return processProperties(false, columns.toArray(new SFunction[0]));
    }

    public ExampleWrapper<T> excludeProperties(SFunction<T, ?>... columns) {
        return processProperties(false, columns);
    }

    /**
     * 选定字段
     *
     * @param columns
     * @return
     */
    public ExampleWrapper<T> selectProperties(List<SFunction<T, ?>> columns) {
        if (columns == null || columns.isEmpty()) {
            return this;
        }

        return processProperties(true, columns.toArray(new SFunction[0]));
    }

    public ExampleWrapper<T> selectProperties(SFunction<T, ?>... columns) {
        return processProperties(true, columns);
    }

    /**
     * @param columns
     * @param includeOrExclude include == true,exclude = false
     * @return
     */
    protected ExampleWrapper<T> processProperties(boolean includeOrExclude, SFunction<T, ?>... columns) {
        if (columns == null || columns.length == 0) {
            return this;
        }
        String[] arrColumns = new String[columns.length];

        for (int i = 0; i < columns.length; i++) {
            arrColumns[i] = columnToString(columns[i]);
        }
        if (includeOrExclude) {
            this.selectProperties(arrColumns);
        } else {
            this.excludeProperties(arrColumns);
        }
        return this;
    }

}